package ms.jasim.console.gui.component;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;

import ms.jacrim.pddl.PddlSolution;
import ms.jasim.framework.PddlModel;
import ms.jasim.framework.SolutionSimulator;
import ms.jasim.framework.SolutionSimulator.Agent;
import ms.jasim.framework.SolutionSimulator.SimulatedAction;
import ms.jasim.framework.SolutionSimulator.TimeSlot;
import ms.spm.IAppContext;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.axis.TickUnitSource;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.general.Dataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYIntervalSeries;
import org.jfree.data.xy.XYIntervalSeriesCollection;

public class SimulationTimelinePanel extends JPanel {


	private static final long serialVersionUID = 1L;
	private ChartPanel chartPanel;
	private JTextArea txtTimeline;

	static class MyBarRenderer extends BarRenderer {
		private int highlightRow = -1;
		private int highlightColumn = -1;

		public void setHighlightedItem(int row, int column) {
			if ((highlightRow == row) && (highlightColumn == column))
				return;
			highlightRow = row;
			highlightColumn = column;
			notifyListeners(new RendererChangeEvent(this));
		}

		@Override
		public Paint getItemOutlinePaint(int row, int column) {
			if ((row == highlightRow) && (column == highlightColumn))
				return Color.yellow;
			return super.getItemOutlinePaint(row, column);
		}
	}
	
	/**
	 * Create the panel
	 */
	public SimulationTimelinePanel() {
		super(new BorderLayout());
		
		JTabbedPane tab = new JTabbedPane();
		add(tab, BorderLayout.CENTER);
		
		tab.add("Chart", chartPanel = new ChartPanel(null));
		tab.add("Simulation", new JScrollPane(txtTimeline = new JTextArea()));
		
		chartPanel.addChartMouseListener(new ChartMouseListener() {

			@Override
			public void chartMouseClicked(ChartMouseEvent arg0) {
				// TODO Auto-generated method stub
				ChartEntity localChartEntity = arg0.getEntity();
			}

			@Override
			public void chartMouseMoved(ChartMouseEvent param) {
				@SuppressWarnings("unused")
				ChartEntity localChartEntity = param.getEntity();
				/*
				 * if (!(localChartEntity instanceof CategoryItemEntity)) {
				 * renderer.setHighlightedItem(-1, -1); return; }
				 * CategoryItemEntity localCategoryItemEntity =
				 * (CategoryItemEntity) localChartEntity; CategoryDataset
				 * localCategoryDataset = localCategoryItemEntity.getDataset();
				 * renderer.setHighlightedItem(localCategoryDataset.getRowIndex(
				 * localCategoryItemEntity.getRowKey()),
				 * localCategoryDataset.getColumnIndex
				 * (localCategoryItemEntity.getColumnKey()));
				 */

			}
		});
	}

	public void setSolution(IAppContext context, PddlModel model, PddlSolution solution) {
		SolutionSimulator sim = new SolutionSimulator(context, model, solution);
		sim.simulate(0, 999);
		setSimulator(sim);
	}
	
	public void setSimulator(SolutionSimulator simulator) {
		createChart(simulator);
		StringBuilder sb = new StringBuilder();
		for (TimeSlot slot : simulator.Timeline) {
			for (SimulatedAction act : slot.actions)
				sb.append(String.format("[%s] %s: %s\n", slot.time, act.getAgent().getName(), act.getAssociateAction().toString()));
			sb.append("\n");
		}
		txtTimeline.setText(sb.toString());
	}
	
	protected void createChart(SolutionSimulator simulator) {
		
		ArrayList<String> agNames = new ArrayList<String>();
		for (SolutionSimulator.Agent ag : simulator.Agents)
			agNames.add(ag.getName());
		
		Collections.sort(agNames);
		
		Dataset ds = createDataset(simulator, agNames);
			
		JFreeChart chart = ChartFactory.createXYBarChart("Solution", "Agent", false, "Time", (IntervalXYDataset) ds, PlotOrientation.HORIZONTAL, true, false, false);
		
		XYPlot plot = (XYPlot) chart.getPlot();
		plot.setRangePannable(true);
	
		MyBarRenderer localMyBarRenderer = new MyBarRenderer();
		localMyBarRenderer.setDrawBarOutline(true);
				
		SymbolAxis localSymbolAxis = new SymbolAxis("Agent", agNames.toArray(new String[] {}));
		localSymbolAxis.setGridBandsVisible(false);
		plot.setDomainAxis(localSymbolAxis);
		
		XYBarRenderer localXYBarRenderer = (XYBarRenderer) plot.getRenderer();
		localXYBarRenderer.setUseYInterval(true);
		plot.setRenderer(localXYBarRenderer);
		
		NumberAxis axis = (NumberAxis) plot.getRangeAxis();
		TickUnitSource units = NumberAxis.createIntegerTickUnits();
		axis.setStandardTickUnits(units);
		   
		chartPanel.setChart(chart);
	}

	private Dataset createDataset(SolutionSimulator simulator, ArrayList<String> agNames) {
		XYIntervalSeriesCollection result = new XYIntervalSeriesCollection();
		
		HashMap<Agent, XYIntervalSeries> series = new HashMap<SolutionSimulator.Agent, XYIntervalSeries>();
		HashMap<SimulatedAction, Boolean> tasks = new HashMap<SolutionSimulator.SimulatedAction, Boolean>();
		
		for (TimeSlot slot : simulator.Timeline) {
			for (SimulatedAction act : slot.actions) {
				XYIntervalSeries s = series.get(act.getAgent());
				if (s == null) {
					series.put(act.getAgent(), s = new XYIntervalSeries(act.getAgent().getName()));
					result.addSeries(s);
				}
				if (!tasks.containsKey(act)) {
					// Task task = new Task(act.getAssociateAction().Name(), new
					// Hour(act.getStart(), new Day()));
					int y = agNames.indexOf(act.getAgent().getName());
					tasks.put(act, true);
					s.add(y, y - 0.2f, y + 0.2f, 0, act.getStart(), act.getEnd() + 1);
					// XYDataItem dataItem = (XYDataItem)
					// s.getDataItem(s.getItemCount() - 1);
				}
			}
		}
		
		return result;
	}
}
